<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="robots" content="noodp" />
        <title>TCP网络编程中connect、listen、accept三者之间的关系 - L_B__</title><meta name="referrer" content="no-referrer">
<meta name="description" content="TCP网络编程中connect、listen、accept三者之间的关系"><meta property="og:title" content="TCP网络编程中connect、listen、accept三者之间的关系" />
<meta property="og:description" content="TCP网络编程中connect、listen、accept三者之间的关系" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://acking-you.github.io/posts/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/" /><meta property="og:image" content="https://acking-you.github.io/logo.png"/><meta property="article:section" content="posts" />
<meta property="article:published_time" content="2022-01-26T00:00:00+00:00" />
<meta property="article:modified_time" content="2022-01-26T00:00:00+00:00" />

<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="https://acking-you.github.io/logo.png"/>

<meta name="twitter:title" content="TCP网络编程中connect、listen、accept三者之间的关系"/>
<meta name="twitter:description" content="TCP网络编程中connect、listen、accept三者之间的关系"/>
<meta name="application-name" content="FeelIt">
<meta name="apple-mobile-web-app-title" content="FeelIt"><meta name="theme-color" content="#ffffff"><meta name="msapplication-TileColor" content="#da532c"><link rel="canonical" href="https://acking-you.github.io/posts/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/" /><link rel="prev" href="https://acking-you.github.io/posts/c&#43;&#43;%E4%B8%8Epython%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%AF%B9%E6%AF%94/" /><link rel="next" href="https://acking-you.github.io/posts/java%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/" /><link rel="stylesheet" href="/css/page.min.css"><link rel="stylesheet" href="/css/home.min.css"><script type="application/ld+json">
    {
        "@context": "http://schema.org",
        "@type": "BlogPosting",
        "headline": "TCP网络编程中connect、listen、accept三者之间的关系",
        "inLanguage": "zh-CN",
        "mainEntityOfPage": {
            "@type": "WebPage",
            "@id": "https:\/\/acking-you.github.io\/posts\/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB\/"
        },"genre": "posts","keywords": "TCP网络编程中connect、listen、accept三者之间的关系","wordcount":  2637 ,
        "url": "https:\/\/acking-you.github.io\/posts\/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB\/","datePublished": "2022-01-26T00:00:00+00:00","dateModified": "2022-01-26T00:00:00+00:00","publisher": {
            "@type": "Organization",
            "name": "作者"},"author": {
                "@type": "Person",
                "name": "作者"
            },"description": "TCP网络编程中connect、listen、accept三者之间的关系"
    }
    </script></head><body data-header-desktop="auto" data-header-mobile="auto"><script>(window.localStorage && localStorage.getItem('theme') ? localStorage.getItem('theme') === 'dark' : ('auto' === 'auto' ? window.matchMedia('(prefers-color-scheme: dark)').matches : 'auto' === 'dark')) && document.body.setAttribute('theme', 'dark');</script>

        <div id="mask"></div><div class="wrapper"><header class="desktop" id="header-desktop">
    <div class="header-wrapper">
        <div class="header-title">
            <a href="/" title="L_B__">L_B__</a>
        </div>
        <div class="menu">
            <div class="menu-inner"><a class="menu-item" href="/posts/"> 文章 </a><a class="menu-item" href="/tags/"> 标签 </a><a class="menu-item" href="/categories/"> 分类 </a><span class="menu-item delimiter"></span><span class="menu-item search" id="search-desktop">
                        <input type="text" placeholder="搜索文章标题或内容..." id="search-input-desktop">
                        <a href="#" class="search-button search-toggle" id="search-toggle-desktop" title="搜索">
                            <i class="fas fa-search fa-fw"></i>
                        </a>
                        <a href="#" class="search-button search-clear" id="search-clear-desktop" title="清空">
                            <i class="fas fa-times-circle fa-fw"></i>
                        </a>
                        <span class="search-button search-loading" id="search-loading-desktop">
                            <i class="fas fa-spinner fa-fw fa-spin"></i>
                        </span>
                    </span><a href="javascript:void(0);" class="menu-item theme-switch" title="切换主题">
                    <i class="fas fa-adjust fa-fw"></i>
                </a>
            </div>
        </div>
    </div>
</header><header class="mobile" id="header-mobile">
    <div class="header-container">
        <div class="header-wrapper">
            <div class="header-title">
                <a href="/" title="L_B__">L_B__</a>
            </div>
            <div class="menu-toggle" id="menu-toggle-mobile">
                <span></span><span></span><span></span>
            </div>
        </div>
        <div class="menu" id="menu-mobile"><div class="search-wrapper">
                    <div class="search mobile" id="search-mobile">
                        <input type="text" placeholder="搜索文章标题或内容..." id="search-input-mobile">
                        <a href="#" class="search-button search-toggle" id="search-toggle-mobile" title="搜索">
                            <i class="fas fa-search fa-fw"></i>
                        </a>
                        <a href="#" class="search-button search-clear" id="search-clear-mobile" title="清空">
                            <i class="fas fa-times-circle fa-fw"></i>
                        </a>
                        <span class="search-button search-loading" id="search-loading-mobile">
                            <i class="fas fa-spinner fa-fw fa-spin"></i>
                        </span>
                    </div>
                    <a href="#" class="search-cancel" id="search-cancel-mobile">
                        取消
                    </a>
                </div><a class="menu-item" href="/posts/" title="">文章</a><a class="menu-item" href="/tags/" title="">标签</a><a class="menu-item" href="/categories/" title="">分类</a><div class="menu-item"><a href="javascript:void(0);" class="theme-switch" title="切换主题">
                    <i class="fas fa-adjust fa-fw"></i>
                </a>
            </div></div>
    </div>
</header><div class="search-dropdown desktop">
    <div id="search-dropdown-desktop"></div>
</div>
<div class="search-dropdown mobile">
    <div id="search-dropdown-mobile"></div>
</div><main class="main">
                <div class="container"><div class="toc" id="toc-auto">
            <h2 class="toc-title">目录</h2>
            <div class="toc-content" id="toc-content-auto"></div>
        </div><article class="page single" data-toc="disable"><div class="featured-image"><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://s4.ax1x.com/2022/01/22/7hhFR1.png"
        data-srcset="https://s4.ax1x.com/2022/01/22/7hhFR1.png, https://s4.ax1x.com/2022/01/22/7hhFR1.png 1.5x, https://s4.ax1x.com/2022/01/22/7hhFR1.png 2x"
        data-sizes="auto"
        alt="https://s4.ax1x.com/2022/01/22/7hhFR1.png"
        title="TCP网络编程中connect、listen、accept三者之间的关系" /></div><div class="single-card" data-image="true"><h2 class="single-title animated flipInX">TCP网络编程中connect、listen、accept三者之间的关系</h2><div class="post-meta">
                <div class="post-meta-line"><span class="post-author"><a href="/" title="Author" rel=" author" class="author"><i class="fas fa-user-circle fa-fw"></i>作者</a></span>&nbsp;<span class="post-category">出版于  <a href="/categories/linux%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/"><i class="far fa-folder fa-fw"></i>Linux网络编程</a></span></div>
                <div class="post-meta-line"><span><i class="far fa-calendar-alt fa-fw"></i>&nbsp;<time datetime="2022-01-26">2022-01-26</time></span>&nbsp;<span><i class="fas fa-pencil-alt fa-fw"></i>&nbsp;约 2637 字</span>&nbsp;
                    <span><i class="far fa-clock fa-fw"></i>&nbsp;预计阅读 6 分钟</span>&nbsp;</div>
            </div>
            
            <hr><div class="details toc" id="toc-static"  data-kept="">
                    <div class="details-summary toc-title">
                        <span>目录</span>
                        <span><i class="details-icon fas fa-angle-right"></i></span>
                    </div>
                    <div class="details-content toc-content" id="toc-content-static"><nav id="TableOfContents">
  <ul>
    <li><a href="#accept函数">accept()函数</a></li>
    <li><a href="#listen函数">listen()函数</a></li>
    <li><a href="#三次握手的连接队列">三次握手的连接队列</a></li>
    <li><a href="#accept函数-1">accept()函数</a>
      <ul>
        <li><a href="#实验">实验</a></li>
        <li><a href="#总结">总结</a></li>
      </ul>
    </li>
  </ul>
</nav></div>
                </div><div class="content" id="content"><blockquote>
<p>基于 TCP 的网络编程开发分为服务器端和客户端两部分，常见的核心步骤和流程如下：</p>
</blockquote>
<figure><a class="lightgallery" href="https://s2.loli.net/2022/01/26/Ric1E3kurq5f6WI.png" title="https://s2.loli.net/2022/01/26/Ric1E3kurq5f6WI.png" data-thumbnail="https://s2.loli.net/2022/01/26/Ric1E3kurq5f6WI.png" data-sub-html="<h2>整个函数调用(image)</h2>">
        <img
            class="lazyload"
            src="/svg/loading.min.svg"
            data-src="https://s2.loli.net/2022/01/26/Ric1E3kurq5f6WI.png"
            data-srcset="https://s2.loli.net/2022/01/26/Ric1E3kurq5f6WI.png, https://s2.loli.net/2022/01/26/Ric1E3kurq5f6WI.png 1.5x, https://s2.loli.net/2022/01/26/Ric1E3kurq5f6WI.png 2x"
            data-sizes="auto"
            alt="https://s2.loli.net/2022/01/26/Ric1E3kurq5f6WI.png" />
    </a><figcaption class="image-caption">整个函数调用(<code>image</code>)</figcaption>
    </figure>
<h2 id="accept函数">accept()函数</h2>
<p>对于客户端的 connect() 函数，该函数的功能为客户端主动连接服务器，建立连接是通过<a href="http://blog.csdn.net/tennysonsky/article/details/45622395" target="_blank" rel="noopener noreffer">三次握手</a>，而<em><strong>这个连接的过程是由内核完成</strong></em>，不是这个函数完成的，这个函数的作用仅仅是通知 Linux 内核，让 Linux 内核自动完成 TCP 三次握手连接，最后把连接的结果返回给这个函数的返回值（成功连接为0， 失败为-1）。</p>
<p>通常的情况，客户端的 connect() 函数默认会一直阻塞，直到<a href="http://blog.csdn.net/tennysonsky/article/details/45622395" target="_blank" rel="noopener noreffer">三次握手</a>成功或超时失败才返回（正常的情况，这个过程很快完成）。</p>
<hr>
<h2 id="listen函数">listen()函数</h2>
<blockquote>
<p>对于服务器，它是被动连接的。举一个生活中的例子，通常的情况下，移动的客服（相当于服务器）是等待着客户（相当于客户端）电话的到来。而这个过程，需要调用listen()函数。</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="cp">#include</span><span class="cpf">&lt;sys/socket.h&gt;</span><span class="cp">
</span><span class="cp"></span><span class="kt">int</span> <span class="nf">listen</span><span class="p">(</span><span class="kt">int</span> <span class="n">sockfd</span><span class="p">,</span> <span class="kt">int</span> <span class="n">backlog</span><span class="p">);</span>
</code></pre></div><p><code>listen()</code> 函数的主要作用就是将套接字(   sockfd   )变成被动的连接监听套接字（被动等待客户端的连接），至于参数 backlog 的作用是设置内核中连接队列的长度（这个长度有什么用，后面做详细的解释），<em><strong>TCP 三次握手也不是由这个函数完成，listen()的作用仅仅告诉内核一些信息。</strong></em></p>
<p>这样的话，当有一个客户端主动连接 <code>connect()</code>，Linux 内核就自动完成<a href="http://blog.csdn.net/tennysonsky/article/details/45622395" target="_blank" rel="noopener noreffer">TCP 三次握手</a>，将建立好的链接自动存储到队列中，如此重复。</p>
<p>所以，只要 TCP 服务器调用了 <code>listen()</code>，客户端就可以通过 <code>connect()</code> 和服务器建立连接，而<strong>这个连接的过程是由内核完成</strong>。</p>
<figure><a class="lightgallery" href="https://s2.loli.net/2022/01/26/mBSOezpYvJFqkVb.png" title="https://s2.loli.net/2022/01/26/mBSOezpYvJFqkVb.png" data-thumbnail="https://s2.loli.net/2022/01/26/mBSOezpYvJFqkVb.png" data-sub-html="<h2>三次握手</h2>">
        <img
            class="lazyload"
            src="/svg/loading.min.svg"
            data-src="https://s2.loli.net/2022/01/26/mBSOezpYvJFqkVb.png"
            data-srcset="https://s2.loli.net/2022/01/26/mBSOezpYvJFqkVb.png, https://s2.loli.net/2022/01/26/mBSOezpYvJFqkVb.png 1.5x, https://s2.loli.net/2022/01/26/mBSOezpYvJFqkVb.png 2x"
            data-sizes="auto"
            alt="https://s2.loli.net/2022/01/26/mBSOezpYvJFqkVb.png" />
    </a><figcaption class="image-caption">三次握手</figcaption>
    </figure>
<hr>
<p>下面为测试的服务器和客户端代码，运行程序时，要先运行服务器，再运行客户端：</p>
<blockquote>
<p>服务器：</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;						</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;sys/socket.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;netinet/in.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;arpa/inet.h&gt;				</span><span class="cp">
</span><span class="cp"></span><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
	<span class="kt">unsigned</span> <span class="kt">short</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">8000</span><span class="p">;</span>	
 
	<span class="kt">int</span> <span class="n">sockfd</span><span class="p">;</span>
	<span class="n">sockfd</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span><span class="c1">// 创建通信端点：套接字
</span><span class="c1"></span>	<span class="k">if</span><span class="p">(</span><span class="n">sockfd</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">perror</span><span class="p">(</span><span class="s">&#34;socket&#34;</span><span class="p">);</span>
		<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span>
	
	<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">my_addr</span><span class="p">;</span>
	<span class="n">bzero</span><span class="p">(</span><span class="o">&amp;</span><span class="n">my_addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">my_addr</span><span class="p">));</span>	     
	<span class="n">my_addr</span><span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">;</span>
	<span class="n">my_addr</span><span class="p">.</span><span class="n">sin_port</span>   <span class="o">=</span> <span class="n">htons</span><span class="p">(</span><span class="n">port</span><span class="p">);</span>
	<span class="n">my_addr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">.</span><span class="n">s_addr</span> <span class="o">=</span> <span class="n">htonl</span><span class="p">(</span><span class="n">INADDR_ANY</span><span class="p">);</span>
	
	<span class="kt">int</span> <span class="n">err_log</span> <span class="o">=</span> <span class="n">bind</span><span class="p">(</span><span class="n">sockfd</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">my_addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">my_addr</span><span class="p">));</span>
	<span class="k">if</span><span class="p">(</span> <span class="n">err_log</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">perror</span><span class="p">(</span><span class="s">&#34;binding&#34;</span><span class="p">);</span>
		<span class="n">close</span><span class="p">(</span><span class="n">sockfd</span><span class="p">);</span>		
		<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span>
	
	<span class="n">err_log</span> <span class="o">=</span> <span class="n">listen</span><span class="p">(</span><span class="n">sockfd</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
	<span class="k">if</span><span class="p">(</span><span class="n">err_log</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">perror</span><span class="p">(</span><span class="s">&#34;listen&#34;</span><span class="p">);</span>
		<span class="n">close</span><span class="p">(</span><span class="n">sockfd</span><span class="p">);</span>		
		<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span>	
	
	<span class="n">printf</span><span class="p">(</span><span class="s">&#34;listen client @port=%d...</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span><span class="n">port</span><span class="p">);</span>
	
	<span class="n">sleep</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>	<span class="c1">// 延时10s
</span><span class="c1"></span> 
	<span class="n">system</span><span class="p">(</span><span class="s">&#34;netstat -an | grep 8000&#34;</span><span class="p">);</span>	<span class="c1">// 查看连接状态
</span><span class="c1"></span>	
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><blockquote>
<p>客户端</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;arpa/inet.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;sys/socket.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;netinet/in.h&gt;</span><span class="cp">
</span><span class="cp"></span><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
	<span class="kt">unsigned</span> <span class="kt">short</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">8000</span><span class="p">;</span>        		<span class="c1">// 服务器的端口号
</span><span class="c1"></span>	<span class="kt">char</span> <span class="o">*</span><span class="n">server_ip</span> <span class="o">=</span> <span class="s">&#34;10.221.20.12&#34;</span><span class="p">;</span>    	<span class="c1">// 服务器ip地址
</span><span class="c1"></span> 
	<span class="kt">int</span> <span class="n">sockfd</span><span class="p">;</span>
	<span class="n">sockfd</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span><span class="c1">// 创建通信端点：套接字
</span><span class="c1"></span>	<span class="k">if</span><span class="p">(</span><span class="n">sockfd</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">perror</span><span class="p">(</span><span class="s">&#34;socket&#34;</span><span class="p">);</span>
		<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span>
	
	<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">server_addr</span><span class="p">;</span>
	<span class="n">bzero</span><span class="p">(</span><span class="o">&amp;</span><span class="n">server_addr</span><span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">server_addr</span><span class="p">));</span> <span class="c1">// 初始化服务器地址
</span><span class="c1"></span>	<span class="n">server_addr</span><span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">;</span>
	<span class="n">server_addr</span><span class="p">.</span><span class="n">sin_port</span> <span class="o">=</span> <span class="n">htons</span><span class="p">(</span><span class="n">port</span><span class="p">);</span>
	<span class="n">inet_pton</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">server_ip</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">server_addr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">);</span>
	
	<span class="kt">int</span> <span class="n">err_log</span> <span class="o">=</span> <span class="n">connect</span><span class="p">(</span><span class="n">sockfd</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">server_addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">server_addr</span><span class="p">));</span>      <span class="c1">// 主动连接服务器
</span><span class="c1"></span>	<span class="k">if</span><span class="p">(</span><span class="n">err_log</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">perror</span><span class="p">(</span><span class="s">&#34;connect&#34;</span><span class="p">);</span>
		<span class="n">close</span><span class="p">(</span><span class="n">sockfd</span><span class="p">);</span>
		<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span>
	
	<span class="n">system</span><span class="p">(</span><span class="s">&#34;netstat -an | grep 8000&#34;</span><span class="p">);</span>	<span class="c1">// 查看连接状态
</span><span class="c1"></span>	
	<span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
 
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><blockquote>
<p>运行结果：<img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://s2.loli.net/2022/01/26/zY3ONF7KUnXJ2fT.jpg"
        data-srcset="https://s2.loli.net/2022/01/26/zY3ONF7KUnXJ2fT.jpg, https://s2.loli.net/2022/01/26/zY3ONF7KUnXJ2fT.jpg 1.5x, https://s2.loli.net/2022/01/26/zY3ONF7KUnXJ2fT.jpg 2x"
        data-sizes="auto"
        alt="https://s2.loli.net/2022/01/26/zY3ONF7KUnXJ2fT.jpg"
        title="https://s2.loli.net/2022/01/26/zY3ONF7KUnXJ2fT.jpg" /></p>
</blockquote>
<hr>
<h2 id="三次握手的连接队列">三次握手的连接队列</h2>
<p>这里详细的介绍一下 <code>listen()</code> 函数的第二个参数（ backlog）的作用：<strong>告诉内核连接队列的长度</strong>。</p>
<blockquote>
</blockquote>
<p>为了更好的理解 backlog 参数，我们必须认识到内核为任何一个给定的监听套接口维护两个队列：</p>
<ol>
<li>未完成连接队列（incomplete connection queue），以某个客户发出并到达服务器，而服务器正在等待完成相应的 TCP <a href="http://blog.csdn.net/tennysonsky/article/details/45622395" target="_blank" rel="noopener noreffer">三次握手</a>过程。这些端口都处于处于 <code>SYN_RCVD</code> 状态。</li>
<li>已完成连接队列（completed connection queue），这些端口处于 <code>ESTABLISHED</code> 状态。</li>
</ol>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://s2.loli.net/2022/01/26/EKudUZo3P8zLnpW.png"
        data-srcset="https://s2.loli.net/2022/01/26/EKudUZo3P8zLnpW.png, https://s2.loli.net/2022/01/26/EKudUZo3P8zLnpW.png 1.5x, https://s2.loli.net/2022/01/26/EKudUZo3P8zLnpW.png 2x"
        data-sizes="auto"
        alt="https://s2.loli.net/2022/01/26/EKudUZo3P8zLnpW.png"
        title="https://s2.loli.net/2022/01/26/EKudUZo3P8zLnpW.png" /></p>
<blockquote>
</blockquote>
<p>当来自客户的 <code>SYN</code> 到达时，<code>TCP</code> 在未完成连接队列中创建一个新项，然后响应<strong>以三次握手的第二个分节：服务器的 SYN 响应</strong>，其中稍带对客户 <code>SYN</code> 的 <code>ACK</code>（即SYN+ACK），这一项一直保留在未完成连接队列中，直到<strong>三次握手的第三个分节（客户对服务器 SYN 的 ACK ）到达或者该项超时为止</strong>（源自Berkeley的实现为这些未完成连接的项设置的超时值为75秒）。</p>
<p>如果三次握手正常完成，该项就<strong>从未完成连接队列移到已完成连接队列的队尾</strong>。</p>
<blockquote>
<p><strong>backlog 参数</strong>历史上被定义为上面两个队列的大小之和，大多数实现默认值为 5，当服务器把这个完成连接队列的某个连接取走后，这个队列的位置又空出一个，这样来回实现动态平衡，但在高并发 web 服务器中此值显然不够。</p>
</blockquote>
<hr>
<h2 id="accept函数-1">accept()函数</h2>
<p>accept()函数功能是，从处于 <code>established</code> 状态的连接<strong>队列头部取出一个已经完成的连接</strong>，如果这个队列没有已经完成的连接，<strong>accept()函数就会阻塞，直到取出队列中已完成的用户连接为止</strong>。</p>
<p>如果，服务器不能及时调用 accept() 取走队列中已完成的连接，队列满掉后会怎样呢？UNP（《unix网络编程》）告诉我们，服务器的连接队列满掉后，服务器不会对再对建立新连接的syn进行应答，所以客户端的 connect 就会返回 ETIMEDOUT。<em><strong>但实际上Linux的并不是这样的</strong></em>！</p>
<h3 id="实验">实验</h3>
<blockquote>
<p>下面为测试代码，服务器 listen() 函数只指定队列长度为 2，客户端有 6 个不同的套接字主动连接服务器，同时，保证客户端的 6 个 connect()函数都先调用完毕，服务器的 accpet() 才开始调用。</p>
</blockquote>
<p>服务端：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;						</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;sys/socket.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;netinet/in.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;arpa/inet.h&gt;	</span><span class="cp">
</span><span class="cp"></span>			
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
	<span class="kt">unsigned</span> <span class="kt">short</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">8000</span><span class="p">;</span>			
	
	<span class="kt">int</span> <span class="n">sockfd</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>   
	<span class="k">if</span><span class="p">(</span><span class="n">sockfd</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">perror</span><span class="p">(</span><span class="s">&#34;socket&#34;</span><span class="p">);</span>
		<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span>
	
	<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">my_addr</span><span class="p">;</span>
	<span class="n">bzero</span><span class="p">(</span><span class="o">&amp;</span><span class="n">my_addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">my_addr</span><span class="p">));</span>	     
	<span class="n">my_addr</span><span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">;</span>
	<span class="n">my_addr</span><span class="p">.</span><span class="n">sin_port</span>   <span class="o">=</span> <span class="n">htons</span><span class="p">(</span><span class="n">port</span><span class="p">);</span>
	<span class="n">my_addr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">.</span><span class="n">s_addr</span> <span class="o">=</span> <span class="n">htonl</span><span class="p">(</span><span class="n">INADDR_ANY</span><span class="p">);</span>
	
	<span class="kt">int</span> <span class="n">err_log</span> <span class="o">=</span> <span class="n">bind</span><span class="p">(</span><span class="n">sockfd</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">my_addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">my_addr</span><span class="p">));</span>
	<span class="k">if</span><span class="p">(</span> <span class="n">err_log</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">perror</span><span class="p">(</span><span class="s">&#34;binding&#34;</span><span class="p">);</span>
		<span class="n">close</span><span class="p">(</span><span class="n">sockfd</span><span class="p">);</span>		
		<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span>
	
	<span class="n">err_log</span> <span class="o">=</span> <span class="n">listen</span><span class="p">(</span><span class="n">sockfd</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>	<span class="c1">// 等待队列为2
</span><span class="c1"></span>	<span class="k">if</span><span class="p">(</span><span class="n">err_log</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">perror</span><span class="p">(</span><span class="s">&#34;listen&#34;</span><span class="p">);</span>
		<span class="n">close</span><span class="p">(</span><span class="n">sockfd</span><span class="p">);</span>		
		<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span>	
	<span class="n">printf</span><span class="p">(</span><span class="s">&#34;after listen</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
	
	<span class="n">sleep</span><span class="p">(</span><span class="mi">20</span><span class="p">);</span>	<span class="c1">//延时 20秒
</span><span class="c1"></span>	
	<span class="n">printf</span><span class="p">(</span><span class="s">&#34;listen client @port=%d...</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span><span class="n">port</span><span class="p">);</span>
 
	<span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
	
	<span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
	<span class="p">{</span>	
	
		<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">client_addr</span><span class="p">;</span>		   
		<span class="kt">char</span> <span class="n">cli_ip</span><span class="p">[</span><span class="n">INET_ADDRSTRLEN</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#34;&#34;</span><span class="p">;</span>	   
		<span class="n">socklen_t</span> <span class="n">cliaddr_len</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">client_addr</span><span class="p">);</span>    
		
		<span class="kt">int</span> <span class="n">connfd</span><span class="p">;</span>
		<span class="n">connfd</span> <span class="o">=</span> <span class="n">accept</span><span class="p">(</span><span class="n">sockfd</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">client_addr</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cliaddr_len</span><span class="p">);</span>       
		<span class="k">if</span><span class="p">(</span><span class="n">connfd</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
		<span class="p">{</span>
			<span class="n">perror</span><span class="p">(</span><span class="s">&#34;accept&#34;</span><span class="p">);</span>
			<span class="k">continue</span><span class="p">;</span>
		<span class="p">}</span>
 
		<span class="n">inet_ntop</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">client_addr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">,</span> <span class="n">cli_ip</span><span class="p">,</span> <span class="n">INET_ADDRSTRLEN</span><span class="p">);</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">&#34;-----------%d------</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="o">++</span><span class="n">i</span><span class="p">);</span>
		<span class="n">printf</span><span class="p">(</span><span class="s">&#34;client ip=%s,port=%d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">cli_ip</span><span class="p">,</span><span class="n">ntohs</span><span class="p">(</span><span class="n">client_addr</span><span class="p">.</span><span class="n">sin_port</span><span class="p">));</span>
		
		<span class="kt">char</span> <span class="n">recv_buf</span><span class="p">[</span><span class="mi">512</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
		<span class="k">while</span><span class="p">(</span> <span class="n">recv</span><span class="p">(</span><span class="n">connfd</span><span class="p">,</span> <span class="n">recv_buf</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">recv_buf</span><span class="p">),</span> <span class="mi">0</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="p">)</span>
		<span class="p">{</span>
			<span class="n">printf</span><span class="p">(</span><span class="s">&#34;recv data ==%s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span><span class="n">recv_buf</span><span class="p">);</span>
			<span class="k">break</span><span class="p">;</span>
		<span class="p">}</span>
		
		<span class="n">close</span><span class="p">(</span><span class="n">connfd</span><span class="p">);</span>     <span class="c1">//关闭已连接套接字
</span><span class="c1"></span>		<span class="c1">//printf(&#34;client closed!\n&#34;);
</span><span class="c1"></span>	<span class="p">}</span>
	<span class="n">close</span><span class="p">(</span><span class="n">sockfd</span><span class="p">);</span>         <span class="c1">//关闭监听套接字
</span><span class="c1"></span>	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>客户端：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;arpa/inet.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;sys/socket.h&gt;</span><span class="cp">
</span><span class="cp">#include</span> <span class="cpf">&lt;netinet/in.h&gt;</span><span class="cp">
</span><span class="cp"></span> 
<span class="kt">void</span> <span class="nf">test_connect</span><span class="p">()</span>
<span class="p">{</span>
	<span class="kt">unsigned</span> <span class="kt">short</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">8000</span><span class="p">;</span>        		<span class="c1">// 服务器的端口号
</span><span class="c1"></span>	<span class="kt">char</span> <span class="o">*</span><span class="n">server_ip</span> <span class="o">=</span> <span class="s">&#34;10.221.20.12&#34;</span><span class="p">;</span>    	<span class="c1">// 服务器ip地址
</span><span class="c1"></span>	
	<span class="kt">int</span> <span class="n">sockfd</span><span class="p">;</span>
	<span class="n">sockfd</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span><span class="c1">// 创建通信端点：套接字
</span><span class="c1"></span>	<span class="k">if</span><span class="p">(</span><span class="n">sockfd</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">perror</span><span class="p">(</span><span class="s">&#34;socket&#34;</span><span class="p">);</span>
		<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span>
	
	<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">server_addr</span><span class="p">;</span>
	<span class="n">bzero</span><span class="p">(</span><span class="o">&amp;</span><span class="n">server_addr</span><span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">server_addr</span><span class="p">));</span> <span class="c1">// 初始化服务器地址
</span><span class="c1"></span>	<span class="n">server_addr</span><span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">;</span>
	<span class="n">server_addr</span><span class="p">.</span><span class="n">sin_port</span> <span class="o">=</span> <span class="n">htons</span><span class="p">(</span><span class="n">port</span><span class="p">);</span>
	<span class="n">inet_pton</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">server_ip</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">server_addr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">);</span>
	
	<span class="kt">int</span> <span class="n">err_log</span> <span class="o">=</span> <span class="n">connect</span><span class="p">(</span><span class="n">sockfd</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">server_addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">server_addr</span><span class="p">));</span>      <span class="c1">// 主动连接服务器
</span><span class="c1"></span>	<span class="k">if</span><span class="p">(</span><span class="n">err_log</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">perror</span><span class="p">(</span><span class="s">&#34;connect&#34;</span><span class="p">);</span>
		<span class="n">close</span><span class="p">(</span><span class="n">sockfd</span><span class="p">);</span>
		<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span>
	
	<span class="n">printf</span><span class="p">(</span><span class="s">&#34;err_log ========= %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">err_log</span><span class="p">);</span>
	
	<span class="kt">char</span> <span class="n">send_buf</span><span class="p">[</span><span class="mi">100</span><span class="p">]</span><span class="o">=</span><span class="s">&#34;this is for test&#34;</span><span class="p">;</span>
	<span class="n">send</span><span class="p">(</span><span class="n">sockfd</span><span class="p">,</span> <span class="n">send_buf</span><span class="p">,</span> <span class="n">strlen</span><span class="p">(</span><span class="n">send_buf</span><span class="p">),</span> <span class="mi">0</span><span class="p">);</span>   <span class="c1">// 向服务器发送信息
</span><span class="c1"></span>	
	<span class="n">system</span><span class="p">(</span><span class="s">&#34;netstat -an | grep 8000&#34;</span><span class="p">);</span>  <span class="c1">// 查看连接状态
</span><span class="c1"></span>	
	<span class="c1">//close(sockfd);
</span><span class="c1"></span><span class="p">}</span>
 
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
	<span class="n">pid_t</span> <span class="n">pid</span><span class="p">;</span>
	<span class="n">pid</span> <span class="o">=</span> <span class="n">fork</span><span class="p">();</span>
	
	<span class="k">if</span><span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="n">pid</span><span class="p">){</span>
 
		<span class="n">test_connect</span><span class="p">();</span>		<span class="c1">// 1
</span><span class="c1"></span>		
		<span class="n">pid_t</span> <span class="n">pid</span> <span class="o">=</span> <span class="n">fork</span><span class="p">();</span>
		<span class="k">if</span><span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="n">pid</span><span class="p">){</span>
			<span class="n">test_connect</span><span class="p">();</span>	<span class="c1">// 2
</span><span class="c1"></span>		
		<span class="p">}</span><span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">pid</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">){</span>
			<span class="n">test_connect</span><span class="p">();</span>	<span class="c1">// 3
</span><span class="c1"></span>		<span class="p">}</span>
		
	<span class="p">}</span><span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">pid</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">){</span>
		
		<span class="n">test_connect</span><span class="p">();</span>	<span class="c1">// 4
</span><span class="c1"></span>		
		<span class="n">pid_t</span> <span class="n">pid</span> <span class="o">=</span> <span class="n">fork</span><span class="p">();</span>
		<span class="k">if</span><span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="n">pid</span><span class="p">){</span>
			<span class="n">test_connect</span><span class="p">();</span>	<span class="c1">// 5
</span><span class="c1"></span>		
		<span class="p">}</span><span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">pid</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">){</span>
			<span class="n">test_connect</span><span class="p">();</span>	<span class="c1">// 6
</span><span class="c1"></span>		<span class="p">}</span>
	
	<span class="p">}</span>
 
	<span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
	
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><blockquote>
<p>服务器调用 accept()函数前延时了 20 秒。保证了客户端的 connect() 全部调用完毕后再调用 accept(),运行结果如下：</p>
</blockquote>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://s2.loli.net/2022/01/26/pXdMg4wTjrUKoe3.jpg"
        data-srcset="https://s2.loli.net/2022/01/26/pXdMg4wTjrUKoe3.jpg, https://s2.loli.net/2022/01/26/pXdMg4wTjrUKoe3.jpg 1.5x, https://s2.loli.net/2022/01/26/pXdMg4wTjrUKoe3.jpg 2x"
        data-sizes="auto"
        alt="https://s2.loli.net/2022/01/26/pXdMg4wTjrUKoe3.jpg"
        title="https://s2.loli.net/2022/01/26/pXdMg4wTjrUKoe3.jpg" /></p>
<blockquote>
<p>客户端运行效果图：</p>
</blockquote>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://s2.loli.net/2022/01/26/Qlp6tFqIgzi1cLD.jpg"
        data-srcset="https://s2.loli.net/2022/01/26/Qlp6tFqIgzi1cLD.jpg, https://s2.loli.net/2022/01/26/Qlp6tFqIgzi1cLD.jpg 1.5x, https://s2.loli.net/2022/01/26/Qlp6tFqIgzi1cLD.jpg 2x"
        data-sizes="auto"
        alt="https://s2.loli.net/2022/01/26/Qlp6tFqIgzi1cLD.jpg"
        title="img" /></p>
<blockquote>
</blockquote>
<p>按照 UNP 的说法，连接队列满后（这里设置长度为 2，发了 6 个连接），以后再调用 connect() 应该统统超时失败，但实际上测试结果是：<strong>有的 connect()立刻成功返回了，有的经过明显延迟后成功返回了</strong>。<strong>对于服务器 accpet() 函数也是这样的结果：有的立马成功返回，有的延迟后成功返回</strong>。</p>
<p>对于上面服务器的代码，我们<strong>把lisen()的第二个参数改为 0</strong> ，重新运行程序，发现：</p>
<p>客户端 connect() 全部返回连接成功（有些会延时）：</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://s2.loli.net/2022/01/26/bjHEUeu7PGtgDaZ.jpg"
        data-srcset="https://s2.loli.net/2022/01/26/bjHEUeu7PGtgDaZ.jpg, https://s2.loli.net/2022/01/26/bjHEUeu7PGtgDaZ.jpg 1.5x, https://s2.loli.net/2022/01/26/bjHEUeu7PGtgDaZ.jpg 2x"
        data-sizes="auto"
        alt="https://s2.loli.net/2022/01/26/bjHEUeu7PGtgDaZ.jpg"
        title="img" /></p>
<p>服务器 accpet() 函数却不能把连接队列的所有连接都取出来：</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://s2.loli.net/2022/01/26/FymxCs4pYXr98JE.jpg"
        data-srcset="https://s2.loli.net/2022/01/26/FymxCs4pYXr98JE.jpg, https://s2.loli.net/2022/01/26/FymxCs4pYXr98JE.jpg 1.5x, https://s2.loli.net/2022/01/26/FymxCs4pYXr98JE.jpg 2x"
        data-sizes="auto"
        alt="https://s2.loli.net/2022/01/26/FymxCs4pYXr98JE.jpg"
        title="img" /></p>
<blockquote>
</blockquote>
<p>对于上面服务器的代码，我们<strong>把lisen()的第二个参数改为大于 6 的数(如 10)</strong>，重新运行程序，发现，客户端 connect() 立马返回连接成功， 服务器 accpet() 函数也立马返回成功。</p>
<h3 id="总结">总结</h3>
<p><strong>TCP 的连接队列满后，Linux 不会如书中所说的拒绝连接</strong>，只是有些会延时连接，<em><strong>但千万注意此时accept()就不一定能把已经建立好的连接全部取出来（如：当队列的长度指定为 0 ）</strong></em>，写程序时服务器的 listen() 的第二个参数最好还是根据需要填写，写太大不好（具体可以看cat /proc/sys/net/core/somaxconn，默认最大值限制是 128），浪费资源，写太小也不好，延时建立连接。</p>
</div><div class="post-footer" id="post-footer">
    <div class="post-info"><div class="post-info-tag"><span><a href="/tags/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/">TCP网络编程中connect、listen、accept三者之间的关系</a>
                </span></div><div class="post-info-line"><div class="post-info-mod">
                <span>更新于 2022-01-26</span>
            </div><div class="post-info-mod"></div>
        </div><div class="post-info-share">
            <span><a href="javascript:void(0);" title="分享到 Twitter" data-sharer="twitter" data-url="https://acking-you.github.io/posts/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/" data-title="TCP网络编程中connect、listen、accept三者之间的关系" data-hashtags="TCP网络编程中connect、listen、accept三者之间的关系"><i class="fab fa-twitter fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Facebook" data-sharer="facebook" data-url="https://acking-you.github.io/posts/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/" data-hashtag="TCP网络编程中connect、listen、accept三者之间的关系"><i class="fab fa-facebook-square fa-fw"></i></a><a href="javascript:void(0);" title="分享到 WhatsApp" data-sharer="whatsapp" data-url="https://acking-you.github.io/posts/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/" data-title="TCP网络编程中connect、listen、accept三者之间的关系" data-web><i class="fab fa-whatsapp fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Line" data-sharer="line" data-url="https://acking-you.github.io/posts/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/" data-title="TCP网络编程中connect、listen、accept三者之间的关系"><i class="fab fa-line fa-fw"></i></a><a href="javascript:void(0);" title="分享到 微博" data-sharer="weibo" data-url="https://acking-you.github.io/posts/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/" data-title="TCP网络编程中connect、listen、accept三者之间的关系" data-image="https://s4.ax1x.com/2022/01/22/7hhFR1.png"><i class="fab fa-weibo fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Myspace" data-sharer="myspace" data-url="https://acking-you.github.io/posts/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/" data-title="TCP网络编程中connect、listen、accept三者之间的关系" data-description="TCP网络编程中connect、listen、accept三者之间的关系"><i data-svg-src="/lib/simple-icons/icons/myspace.min.svg"></i></a><a href="javascript:void(0);" title="分享到 Blogger" data-sharer="blogger" data-url="https://acking-you.github.io/posts/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/" data-title="TCP网络编程中connect、listen、accept三者之间的关系" data-description="TCP网络编程中connect、listen、accept三者之间的关系"><i class="fab fa-blogger fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Evernote" data-sharer="evernote" data-url="https://acking-you.github.io/posts/tcp%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%ADconnectlistenaccept%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/" data-title="TCP网络编程中connect、listen、accept三者之间的关系"><i class="fab fa-evernote fa-fw"></i></a></span>
        </div></div><div class="post-nav"><a href="/posts/c&#43;&#43;%E4%B8%8Epython%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%AF%B9%E6%AF%94/" class="prev" rel="prev" title="C&#43;&#43;与python文件系统对比"><i class="fas fa-angle-left fa-fw"></i>Previous Post</a>
            <a href="/posts/java%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/" class="next" rel="next" title="Java网络编程">Next Post<i class="fas fa-angle-right fa-fw"></i></a></div></div>
</div></article></div>
            </main>
            <footer class="footer"><div class="footer-container"><div class="footer-line">由 <a href="https://gohugo.io/" target="_blank" rel="noopener noreffer" title="Hugo 0.86.0">Hugo</a> 强力驱动 | 主题 - <a href="https://github.com/khusika/FeelIt" target="_blank" rel="noopener noreffer" title="FeelIt 1.0.1"><i class="fas fa-hand-holding-heart fa-fw"></i> FeelIt</a>
        </div><div class="footer-line" itemscope itemtype="http://schema.org/CreativeWork"><i class="far fa-copyright fa-fw"></i><span itemprop="copyrightYear">2023</span><span class="author" itemprop="copyrightHolder">&nbsp;<a href="/"></a></span></div>
</div>
</footer>
        </div>

        <div id="fixed-buttons"><a href="#" id="back-to-top" class="fixed-button" title="回到顶部">
                <i class="fas fa-chevron-up fa-fw"></i>
            </a></div><link rel="stylesheet" href="/lib/fontawesome-free/all.min.css"><link rel="stylesheet" href="/lib/animate/animate.min.css"><link rel="stylesheet" href="/lib/katex/katex.min.css"><link rel="stylesheet" href="/lib/katex/copy-tex.min.css"><script src="/lib/autocomplete/autocomplete.min.js"></script><script src="/lib/lunr/lunr.min.js"></script><script src="/lib/lunr/lunr.stemmer.support.min.js"></script><script src="/lib/lunr/lunr.zh.min.js"></script><script src="/lib/lazysizes/lazysizes.min.js"></script><script src="/lib/clipboard/clipboard.min.js"></script><script src="/lib/sharer/sharer.min.js"></script><script src="/lib/katex/katex.min.js"></script><script src="/lib/katex/auto-render.min.js"></script><script src="/lib/katex/copy-tex.min.js"></script><script src="/lib/katex/mhchem.min.js"></script><script>window.config={"code":{"copyTitle":"复制到剪贴板","maxShownLines":200},"comment":{},"math":{"delimiters":[{"display":true,"left":"$$","right":"$$"},{"display":true,"left":"\\[","right":"\\]"},{"display":false,"left":"$","right":"$"},{"display":false,"left":"\\(","right":"\\)"}],"strict":false},"search":{"highlightTag":"em","lunrIndexURL":"/index.json","lunrLanguageCode":"zh","lunrSegmentitURL":"/lib/lunr/lunr.segmentit.js","maxResultLength":100,"noResultsFound":"没有找到结果","snippetLength":50,"type":"lunr"}};</script><script src="/js/theme.min.js"></script></body></html>
